#!/usr/bin/bash

#--------------------------------添加错误捕获-------------------------------------#
# -e 当命令失败时, 退出脚本
# -u 当使用未定义的变量时, 退出脚本
# -o pipefail 当管道中的任何命令失败时, 退出脚本
# set -euo pipefail
# trap 'echo "error: 脚本在行 $LINENO 出现错误: $BASH_COMMAND"' ERR

#----------------------------------环境变量---------------------------------------#
RED='\E[1;31m'                              # 红
GREEN='\E[1;32m'                            # 绿
YELOW='\E[1;33m'                            # 黄
BLUE='\E[1;34m'                             # 蓝
PINK='\E[1;35m'                             # 粉红
SHAN='\E[33;5m'                             # 黄色闪烁警示
RES='\E[0m'                                 # 清除颜色
INFO='√'                                    # 信息输出显示符
ERROR='×'                                   # 错误输出显示符
WARN='!'                                    # 警告输出显示符
LogFile="${LOG_FILE:-/tmp/default_log.log}" # 日志文件路径
Version="v0.0.1"                            # 版本号

#----------------------------------函数模块---------------------------------------#
# PrintInfo 打印正常信息
PrintInfo() {
    Green "[${INFO}] ${1}"
}

# PrintError 打印错误信息
PrintError() {
    Red "[${ERROR}] ${1}"
}

# PrintWarn 打印警告信息
PrintWarn() {
    Yellow "[${WARN}] ${1}"
}

# Red 输出红色信息
Red() {
    echo -e "${RED}${1}${RES}"
}

# Green 输出绿色信息
Green() {
    echo -e "${GREEN}${1}${RES}"
}

# Yellow 输出黄色信息
Yellow() {
    echo -e "${YELOW}${1}${RES}"
}

# Pink 输出粉色信息
Pink() {
    echo -e "${PINK}${1}${RES}"
}

# Blue 输出蓝色信息
Blue() {
    echo -e "${BLUE}${1}${RES}"
}

# Shan 输出黄色闪烁信息
Shan() {
    echo -e "${SHAN}${1}${RES}"
}

# 初始化日志文件和目录
InitLog() {
    # 检查日志文件是否存在，如果不存在则创建
    if [ ! -f "${LogFile}" ]; then
        # 确保日志文件的所在目录存在
        mkdir -p "$(dirname "${LogFile}")" || {
            PrintError "无法创建日志文件目录: $(dirname "${LogFile}")"
            return 1
        }
        # 日志文件不存在，尝试创建
        true >"${LogFile}" || {
            PrintError "无法创建日志文件: ${LogFile}"
            return 1
        }
    fi

    # 检查是否有足够的权限写入日志文件
    if [ ! -w "${LogFile}" ]; then
        PrintError "没有权限写入日志文件: ${LogFile}"
        return 1
    fi

    return 0
}

# 写入日志函数
WriteLog() {
    # 检查是否提供了足够的参数
    if [ "$#" -ne 2 ]; then
        PrintError "Usage: WriteLog <logLevel> <logMessage>"
        return 1
    fi

    # 检查日志级别是否合法
    case "$1" in
    INFO | WARN | ERROR)
        # 合法的日志级别, 继续执行
        ;;
    *)
        PrintError "无效日志级别: $1。合法日志级别为 INFO、WARN、ERROR, 请使用上述合法级别。"
        return 1
        ;;
    esac

    # 检查日志消息是否为空
    if [ -z "$2" ]; then
        PrintError "Log message cannot be empty."
        return 1
    fi

    # 获取日志级别
    logLevel=$(echo "$1" | tr '[:lower:]' '[:upper:]')

    # 获取日志消息
    logMessage="$2"

    # 获取当前日期和时间
    currentDate=$(date "+%Y-%m-%d %H:%M:%S")

    # 通过 printf 构造日志消息并存储到logEntry变量中
    printf -v logEntry "%-18s [%-5s] %s" "${currentDate}" "${logLevel}" "${logMessage}"

    # 根据日志级别输出到控制台
    case "${logLevel}" in
    INFO)
        PrintInfo "${logMessage}"
        ;;
    WARN)
        PrintWarn "${logMessage}"
        ;;
    ERROR)
        PrintError "${logMessage}"
        ;;
    esac

    # 写入到日志文件(echo自动换行)
    echo "${logEntry}" >>"${LogFile}"
}

# 日志旋转函数
LogRotate() {
    # 捕获错误
    trap 'echo "error: 脚本在行 $LINENO 出现错误: $BASH_COMMAND"' ERR

    # 检查日志文件是否存在
    if [ ! -f "${LogFile}" ]; then
        return 0
    fi

    # 定义日志文件的最大大小和最多保留的文件数量
    local max_size=1048576                        # 1MB
    local max_files=5                             # 最多保留5个日志文件
    local log_file_size=$(stat -c%s "${LogFile}") # 获取日志文件的大小

    if [ "${log_file_size}" -ge "${max_size}" ]; then
        # 删除最旧的日志文件(如果存在)
        if [ -f "${LogFile}.${max_files}" ]; then
            rm -f "${LogFile}.${max_files}"
        fi

        # 从最大的日志文件编号开始，逐个重命名
        for ((i = max_files - 1; i >= 1; i--)); do
            if [ -f "${LogFile}.${i}" ]; then
                mv "${LogFile}.${i}" "${LogFile}.$((i + 1))"
            fi
        done

        # 将当前日志文件重命名为 LogFile.1
        mv "${LogFile}" "${LogFile}.1"

        # 创建一个新的空日志文件
        >"${LogFile}"
    fi
}

# PrintHelp 打印帮助信息
PrintHelp() {
    local list
    local item
    # 定义一个列表, 每个元素包含两个部分, 用'.'分隔
    list=(
        "1.[-h|--help],获取帮助信息;"
        "2.[-v|--version],输出版本信息;"
        "3.[-f|--file],测试参数;"
    )
    # 输出分隔线
    Yellow "$(printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' '-')"
    Green " app-help:"
    for item in "${list[@]}"; do
        local list1
        # 提取列表项的第一个元素, 并使用 Pink 函数进行颜色处理
        list1=$(Pink "$(echo "${item}" | awk -F'.' '{print $1}')")
        local list2
        # 提取列表项的第二个元素
        list2=$(echo "${item}" | awk -F'.' '{print $2}')
        echo "      ${list1}.${list2}"
    done
    # 输出分隔线
    Yellow "$(printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' '-')"
}

# 定义一个函数, 用于输出版本信息
ShowVersion() {
    echo "$0 Version: ${Version}"
}

main() {
    # 捕获错误
    trap 'echo "error: 脚本在行 $LINENO 出现错误: $BASH_COMMAND"' ERR

    # 检查是否提供了足够的参数
    if [ "$#" -lt 1 ]; then
        PrintError "Usage: $0 <command> [options]"
        PrintHelp
        exit 1
    fi

    # 初始化日志文件
    if ! InitLog; then
        PrintError "日志初始化失败"
        exit 1
    fi

    # 日志旋转
    LogRotate

    # 解析命令行参数
    while [[ $# -gt 0 ]]; do
        case "$1" in
        -h | --help)
            PrintHelp
            exit 0
            ;;
        -v | --version)
            ShowVersion
            exit 0
            ;;
        -f | --file)
            # 测试参数
            if [ -z "$2" ]; then
                PrintError "参数 -f 或 --file 后面必须跟一个文件名"
                exit 1
            fi
            # 将文件名存储在变量中
            FileName="$2"
            # 输出文件名
            PrintInfo "文件名: $FileName"
            # 丢弃前两个参数
            shift 2
            exit 0
            ;;
        *)
            PrintError "未知参数: $1"
            PrintHelp
            exit 1
            ;;
        esac

        # 丢弃已处理的参数
        shift
    done
}

#-----------------------------------main-----------------------------------------#
main "$@"
